'use strict';
const Axios = require('axios');
const LZString = require('../lib/LZStringJQS.js');
const util = require('../lib/util.js');
const querystring = require('querystring');
const path = require('path');
const downloadpath = path.join(__dirname, '../lib/designImgs/');
const fs = require('fs');
const https = require('https');
let cookies = [];
let latestDate = '';

async function getParam(ctx, count = 3) {
  if (count < 0) {
    return null;
  }
  const ua = util.getUa();
  const respose = await Axios({
    method: 'get',
    url: 'https://www3.wipo.int/designdb/hague/en/index.jsp#',
    proxy: false,
    timeout: 120000,
    headers: {
      'user-agent': ua,
    },
  });
  cookies = [];
  for (const cookieStr of respose.headers['set-cookie']) {
    const cookie = {};
    cookieStr.split(';').forEach(Cookie => {
      const parts = Cookie.split('=');
      cookie[parts[0].trim()] = (parts[1] || '').trim();
    });
    cookies.push(cookie);
  }
  const resposeData = respose.data || null;
  try {
    // var len = resposeData.length;
    // var trafficStatistics = await ctx.app.redis.get('traffic-statistics') || 0;
    // await ctx.app.redis.set('traffic-statistics', len + Number(trafficStatistics));
    const qk = await util.findQkByDoc(resposeData);
    const fo = await util.findDesFoByDoc(resposeData);
    if (qk && fo) {
      ctx.app.logger.info(`qk: ${qk}, fo: ${fo}`);
      return { qk, fo };
    }
    return await getParam(ctx, --count);
  } catch (error) {
    ctx.app.logger.error('getParam error %s', error.message, error.stack);
    return await getParam(ctx, --count);
  }
}

async function docList(t, ctx, queryBase, tunnelProxy, nums, upStart, vals) {
  const respData = {};
  const setCookie = cookies;
  const data = `qz=${queryBase}`;
  const ua = util.getUa();
  const respose = await Axios({
    method: 'post',
    url: 'https://www3.wipo.int/designdb/hague/jsp/select.jsp',
    data,
    timeout: 30000,
    proxy: false,
    httpsAgent: tunnelProxy,
    headers: {
      Host: 'www3.wipo.int',
      'User-Agent': ua,
      Accept: 'application/json, text/javascript, */*; q=0.01',
      'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
      'Accept-Encoding': 'gzip, deflate, br',
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
      Referer: 'https://www3.wipo.int/designdb/hague/en/index.jsp#',
      'X-Requested-With': 'XMLHttpRequest',
      Cookie: setCookie.join('; '),
    },
  }).catch(error => {
    throw new Error(error.message);
  });
  try {
    const resposeData = respose.data || {};
    const resp = resposeData.response || {};
    if (resposeData.qi && resp.docs.length > 0) {
      // resp.qi = resposeData.qi;
      // resp.qk = resposeData.qk;
      // resp.lastUpdated = resposeData.lastUpdated;
      const docs = resp.docs;
      // const source = docs[0].SOURCE;
      // var numFound = resp.numFound
      const docslist = [];
      // if(Number(numFound) > Number(startFrom) && i == 0) {nums = Math.ceil((Number(numFound)-Number(startFrom))/100)}
      if (!t) {
        if (docs.length >= 30) {
          nums += 1;
        }
        if (upStart === 0) {
          const teInfor = {};
          teInfor.startFrom = vals.startFrom;
          teInfor.totalNums = vals.totalNums;
          teInfor.latestDate = Date.parse(docs[0].RD) - 28800000;
          await ctx.app.redis.hset('design_config', 'config', querystring.stringify(teInfor));
          latestDate = teInfor.latestDate;
        }
      } else {
        docs.forEach(function(item) {
          if (Date.parse(item.RD) - 28800000 >= vals.latestDate && vals.latestDate > ctx.app.config.datas_start_time) {
            docslist.push(item);
          }
        });
        if (docslist.length < 1) {
          ctx.app.logger.info('new-design: noData update!');
          respData.nums = nums;
          return respData;
        }
        if (docslist.length >= 30) {
          nums += 1;
        }
        resp.docs = docslist;
      }
      // respData.resp = resp;
      // save dates
      await saveData(ctx, resp.docs);
      const param = {};
      param.ctx = ctx;
      param.vals = vals;
      param.t = t;
      // param.latestDate = latestDate;
      await saveDataStatus(resp, param);
    } else {
      ctx.app.logger.error(`${t}//design//startFrom(${upStart})//resp(${JSON.stringify(resp)})`);
    }
  } catch (error) {
    ctx.app.logger.error(`${t}//design//startFrom(${upStart})//resposeData(${JSON.stringify(respose.data)}): get resp fail!: `, error.message);
  }
  respData.nums = nums;
  return respData;
}

async function saveImgs(imgs) {
  imgs.forEach(img => {
    const imgUrl = 'https://www.wipo.int/idpub/' + img.slice(0, -7) + 's' + img.slice(-7) + '.jpg';
    https.get(imgUrl, res => {
      let imgData = '';
      res.setEncoding('binary');
      res.on('data', chunk => {
        imgData += chunk;
      });
      res.on('end', () => {
        fs.writeFile(downloadpath + `${img}.jpg`, imgData, 'binary', error => {
          if (error) {
            console.log('下载失败', error);
          } else {
            console.log(`${img}下载成功！`);
          }
        });
      });
    });
  });
}

async function saveData(ctx, resps) {
  resps.forEach(resp => {
    const IRN = resp.IRN;
    const HOL = resp.HOL;
    const LCS = resp.LCS;
    const PROD_EN = resp.PROD_EN;
    const DS = resp.DS;
    const IMG = resp.IMG;
    const RD = resp.RD;
    const data = {
      regNo: IRN.slice(0, 1) + 'M/' + IRN.slice(1),
      holder: HOL,
      locarno_cl: LCS,
      ind_prod: PROD_EN,
      designations: DS,
      image: IMG,
      regDate: Date.parse(RD) - 28800000,
    };
    ctx.service.tortious.addTortDesign(data);
    // save imgs
    saveImgs(IMG);
    // console.log('insert tort_designs成功!');
  });
}

async function saveDataStatus(repsarr, data) {
  const teInfor = {};
  const ctx = data.ctx;
  const vals = data.vals;
  const t = data.t;
  // const latestDate = data.latestDate;
  // const sour = repsarr.docs[0].SOURCE;
  const nfd = repsarr.numFound;
  const ups = Number(repsarr.start);
  // teInfor.status = vals.status;
  if (!t) {
    teInfor.startFrom = ups + repsarr.docs.length;
    teInfor.totalNums = vals.totalNums;
    if (latestDate) {
      teInfor.latestDate = latestDate;
    } else {
      teInfor.latestDate = vals.latestDate;
    }
    const oldVals = await ctx.app.redis.hget('design_config', 'config');
    const oldSf = querystring.parse(oldVals).startFrom;
    if (Number(oldSf) < teInfor.startFrom) {
      if (teInfor.startFrom >= nfd) {
        teInfor.startFrom = '-1';
      }
      await ctx.app.redis.hset('design_config', 'config', querystring.stringify(teInfor));
    }
  } else {
    if (ups === 0) {
      teInfor.startFrom = vals.startFrom;
      teInfor.totalNums = nfd;
      teInfor.latestDate = Date.parse(repsarr.docs[0].AD) - 28800000;
      await ctx.app.redis.hset('design_config', 'config', querystring.stringify(teInfor));
    }
  }
}

async function main(t, ctx, app) {
  // spider
  let tunnelProxy;
  const maxConn = app.config.mysql_max_connections;
  const params = await getParam(ctx);
  if (!params) {
    ctx.app.logger.error('getParam fail!');
    return;
  }
  const qk = `0-${params.qk}`;
  // const fo = params.fo;
  const queryCofig = app.config.queryCofigDes;
  queryCofig.qi = qk;
  // queryCofig._ = fo;
  const statusInfo = {
    status: 0,
    latestDate: Date.now(),
  };
  await app.redis.hset('design_config', 'status', querystring.stringify(statusInfo));
  let confVal = await app.redis.hget('design_config', 'config');
  confVal = querystring.parse(confVal);
  const startFrom = confVal.startFrom;
  // totalNums = confVal.totalNums;
  if (!t && startFrom === '-1') {
    app.logger.info('all-design finish!: spider end!');
    return;
  }
  if (t && startFrom === '0') {
    app.logger.info('new-design finish!: all-tortious has not been run!');
    return;
  }
  let nums = 1;
  let errNums = 0;
  let reqListArr = [];
  // get response
  for (let i = 0; i < nums; i++) {
    try {
      let upStart = 0;
      if (reqListArr.length >= maxConn) break;
      if (!t) {
        upStart = Number(startFrom) + i * 30;
      } else {
        upStart = 0;
      }
      queryCofig.p.start = upStart;
      const queryBase = LZString.getCurrentStateString(queryCofig);
      if (!queryBase) {
        app.logger.error('get queryBase fail!');
        return;
      }
      try {
        tunnelProxy = await util.initTunnelProxy();
      } catch (error) {
        if (t) {
          reqListArr = [];
        }
        app.logger.error('get proxy fail!: %s', error.message);
        break;
      }
      if (tunnelProxy) {
        const respData = await docList(t, ctx, queryBase, tunnelProxy, nums, upStart, confVal);
        nums = respData.nums;
        if (respData.resp) {
          reqListArr.push(respData.resp);
          // app.logger.info(`${t}//${te}//startFrom(${upStart})//length(${respData.resp.docs.length}): get resp ok!`);
        }
      } else {
        throw new Error('tunnelProxy is null');
      }
    } catch (error) {
      if (errNums < 500) {
        errNums++;
        i--;
        try {
          tunnelProxy = await util.initTunnelProxy();
        } catch (error) {
          if (t) {
            reqListArr = [];
          }
          app.logger.error('get proxy fail!: %s', error.message);
          break;
        }
      }
    }
  }

}


module.exports = app => {
  return {
    schedule: {
      interval: app.config.all_schedule.interval,
      type: 'worker',
      immediate: true,
      disable: false,
    },
    async task(ctx) {
      // startStatus: 0--closed, 1--run all and new, 2--run new
      const statusVuls = await ctx.app.redis.hget('design_config', 'status');
      let startStatus = querystring.parse(statusVuls).status;
      const startDate = querystring.parse(statusVuls).latestDate;
      if (startStatus === '0') {
        if (Date.now() - startDate <= app.config.run_max_time) {
          app.logger.info('design spider is runing or closed!');
          return;
        }
        startStatus = '1';
      }
      try {
        if (startStatus === '1') {
          // main: 0--run all, 1--run new
          const p = [];
          const result = await main(0, ctx, app);
          p.push(result);
          await Promise.all(p).then();
        }
        await main(1, ctx, app);
      } catch (error) {
        app.logger.error(`design task err; ${error}`);
        await app.redis.hset('design_record', util.nowstr(), `task error: ${error}`);
      } finally {
        const statusInfo = {
          status: startStatus,
          latestDate: Date.now(),
        };
        await app.redis.hset('design_config', 'status', querystring.stringify(statusInfo));
      }
    },
  };
};
